home *** CD-ROM | disk | FTP | other *** search
- /* $Id: cbgame.c,v 1.1.1.1 1993/06/21 11:11:59 anjo Exp $
- *
- * File cbgame.c
- * Part of ChessBase utilities file format (CBUFF)
- * Author Anjo Anjewierden, anjo@swi.psy.uva.nl
- * Purpose Internal representation of a ChessBase game
- * Works with GNU CC 2.4.5
- *
- * Notice Copyright (c) 1993 Anjo Anjewierden
- *
- * History 09/06/93 (Created)
- * 31/10/93 (Last modified)
- */
-
-
- /*------------------------------------------------------------
- * Directives
- *------------------------------------------------------------*/
-
- #include "cbuff.h"
-
-
- /*------------------------------------------------------------
- * Definitions
- *------------------------------------------------------------*/
-
- static bool extractVariationsCbGame(CbGame cg, Game game);
-
-
- /*------------------------------------------------------------
- * Initialisation
- *------------------------------------------------------------*/
-
- CbGame
- newCbGame()
- { CbGame cg;
-
- cg = alloc(sizeof(struct cbgame));
- cg->header = newCbHeader();
- cg->text = NULL;
- cg->moves = NULL;
- cg->comments = NULL;
- cg->position = NULL;
- cg->textLength = 0;
- cg->movesLength = 0;
- cg->commentLength = 0;
-
- return cg;
- }
-
-
- void
- freeCbGame(CbGame cg)
- { if (cg->text)
- unalloc(cg->text);
- if (cg->moves)
- unalloc(cg->moves);
- if (cg->comments)
- unalloc(cg->comments);
- freeCbHeader(cg->header);
- unalloc(cg);
- }
-
-
- void
- resetCbGame(CbGame cg)
- { if (cg->text)
- unalloc(cg->text);
- if (cg->moves)
- unalloc(cg->moves);
- if (cg->comments)
- unalloc(cg->comments);
- resetCbHeader(cg->header);
- cg->text = NULL;
- cg->moves = NULL;
- cg->comments = NULL;
- cg->textLength = 0;
- cg->movesLength = 0;
- cg->commentLength = 0;
- }
-
-
- /*------------------------------------------------------------
- * Reading
- *------------------------------------------------------------*/
-
- long
- readCbGame(CbGame cg, CBase cb, long no)
- { long pos; /* Position in file */
- unsigned char h[14]; /* Undecoded game header */
- CbHeader ch = cg->header; /* Game header */
- long rawBytes = 0;
-
- resetCbGame(cg);
- environmentError(cb, NULL, no);
- if (no < 1 || no > getNoGamesCBase(cb))
- { setError(ERR_GAME_NUMBER_OUT_OF_RANGE);
- return (long) NULL;
- }
-
- pos = getIndexGameCBase(cb, no);
- if (fseek(cb->cbf, pos, 0))
- { setError(ERR_CANNOT_SEEK);
- return (long) NULL;
- }
-
- if (fread(h,1,14,cb->cbf) != 14)
- { setError(ERR_CANNOT_READ_HEADER);
- return (long) NULL;
- }
- rawBytes += 14;
-
- initCbHeader(ch, h);
- if (foundError())
- return (long) NULL;
-
- cg->textLength = playersLengthCbHeader(ch) + sourceLengthCbHeader(ch);
- cg->movesLength = movesLengthCbHeader(ch);
- cg->commentLength = commentLengthCbHeader(ch);
-
- cg->text = alloc(cg->textLength);
- cg->moves = alloc(cg->movesLength);
- cg->comments = alloc(cg->commentLength);
-
- if (fread(cg->text,1,cg->textLength,cb->cbf) != cg->textLength)
- { setError(ERR_CANNOT_READ_TEXT);
- return (long) NULL;
- }
- rawBytes += cg->textLength;
-
- if (fread(cg->moves,1,cg->movesLength,cb->cbf) != cg->movesLength)
- { setError(ERR_CANNOT_READ_MOVES);
- return (long) NULL;
- }
- rawBytes += cg->movesLength;
-
- if (fread(cg->comments,1,cg->commentLength,cb->cbf) != cg->commentLength)
- { setError(ERR_CANNOT_READ_COMMENTS);
- return (long) NULL;
- }
- rawBytes += cg->commentLength;
-
- if (!fullGameCbHeaderP(ch))
- { unsigned char nextMove;
- unsigned char board[32];
- int file, rank;
-
- if (fread(board,1,32,cb->cbf) != 32)
- { setError(ERR_CANNOT_READ_POSITION);
- return (long) NULL;
- }
- rawBytes += 32;
- if (fread(&nextMove,1,1,cb->cbf) != 1)
- { setError(ERR_CANNOT_READ_MOVE_NUMBER);
- return (long) NULL;
- }
- rawBytes += 1;
-
- cg->nextMove = ((short) nextMove) + 1;
-
- for (rank=0; rank<8; rank++)
- { for (file=0; file<8; file+=2)
- { unsigned char b = board[rank*4+file/2];
-
- cg->board[makeSquare(file,rank)] = (Piece) (b >> 4);
- cg->board[makeSquare(file+1,rank)] = (Piece) (b & 0xf);
- }
- }
- }
-
- { unsigned char k;
- int i;
- int l = cg->textLength;
-
- k = 3*l;
- for (i=l-1; i>=0; i--)
- { cg->text[i] ^= k;
- k *= 3;
- }
- }
-
- { unsigned char k;
- int i;
- int l = cg->movesLength;
-
- k = 7*(l+1);
- for (i=l-1; i>0; i--)
- { k *= 7;
- cg->moves[i] ^= k;
- }
- }
-
- return rawBytes;
- }
-
-
- /*------------------------------------------------------------
- * Counting
- *------------------------------------------------------------*/
-
- long
- countCbGame(CbGame cg, CBase cb, long no)
- { long pos; /* Position in file */
- unsigned char h[14]; /* Undecoded game header */
- CbHeader ch = cg->header; /* Game header */
- long rawBytes = 0;
-
- resetCbGame(cg);
- environmentError(cb, NULL, no);
- if (no < 1 || no > getNoGamesCBase(cb))
- { setError(ERR_GAME_NUMBER_OUT_OF_RANGE);
- return (long) NULL;
- }
-
- pos = getIndexGameCBase(cb, no);
- if (fseek(cb->cbf, pos, 0))
- { setError(ERR_CANNOT_SEEK);
- return (long) NULL;
- }
-
- if (fread(h,1,14,cb->cbf) != 14)
- { setError(ERR_CANNOT_READ_HEADER);
- return (long) NULL;
- }
- rawBytes += 14;
-
- initCbHeader(ch, h);
- if (foundError())
- return (long) NULL;
-
- cg->textLength = playersLengthCbHeader(ch) + sourceLengthCbHeader(ch);
- cg->movesLength = movesLengthCbHeader(ch);
- cg->commentLength = commentLengthCbHeader(ch);
-
- rawBytes += cg->textLength;
- rawBytes += cg->movesLength;
- rawBytes += cg->commentLength;
-
- if (!fullGameCbHeaderP(ch))
- { rawBytes += 32;
- rawBytes += 1;
- }
-
- return rawBytes;
- }
-
-
- bool
- extractHeaderCbGame(CbGame cg, Game game)
- { unsigned int slen;
- unsigned int plen;
- CbHeader ch = cg->header;
-
- game->year = yearCbHeader(ch);
-
- switch(ch->result)
- { case 0: game->result = BLACK_WINS; break;
- case 1: game->result = DRAW; break;
- case 2: game->result = WHITE_WINS; break;
- case 3: game->result = NO_RESULT; break;
- case 7: game->result = WHITE_WINNING; break;
- case 11: game->result = WHITE_ADVANTAGE; break;
- case 15: game->result = WHITE_BETTER; break;
- case 19: game->result = EQUALITY; break;
- case 23: game->result = UNCLEAR; break;
- case 27: game->result = BLACK_BETTER; break;
- case 31: game->result = BLACK_ADVANTAGE; break;
- case 35: game->result = BLACK_WINNING; break;
- case 39: game->result = COMPENSATION; break;
- case 43: game->result = COMPENSATION; break;
- case 47: game->result = WITH_COUNTERPLAY; break;
- case 51: game->result = WITH_INITIATIVE; break;
- case 55: game->result = WITH_ATTACK; break;
- case 59: game->result = TIME_TROUBLE; break;
- case 63: game->result = ONLY_MOVE; break;
- default: setError(ERR_ILLEGAL_RESULT);
- game->result = NO_RESULT;
- }
-
- plen = playersLengthCbHeader(ch);
- slen = sourceLengthCbHeader(ch);
-
- game->eloWhite = whiteEloCbHeader(ch);
- game->eloBlack = blackEloCbHeader(ch);
-
- game->moves = movesCbHeader(ch);
- game->plies = game->moves * 2;
- strcpy(game->eco, ecoCbHeader(ch));
-
- game->flags |= (flags2bit6CbHeader(ch) ? GAME_FLAGS2_BIT6 : 0);
- game->flags |= (deletedCbHeaderP(ch) ? GAME_DELETED : 0);
- game->flags |= (markedCbHeaderP(ch) ? GAME_MARKED : 0);
-
- strncpy(game->players, cg->text, plen);
- game->players[plen] = '\0';
-
- strncpy(game->source, &cg->text[plen], slen);
- game->source[slen] = '\0';
-
- if (!fullGameCbHeaderP(ch))
- { Position p;
-
- p = game->position = newPosition();
- memcpy(p->board, cg->board, sizeof(Piece) * 64);
- p->nextMove = cg->nextMove;
- p->toMove = (ch->flags1 & COLOUR_TO_MOVE_MASK ? BLACK : WHITE);
- p->enPassant = ch->flags2 & EN_PASSANT_MASK;
- p->castling = 0;
- if (ch->flags1 & WHITE_CASTLE_LONG_MASK)
- p->castling |= WHITE_LONG;
- if (ch->flags1 & WHITE_CASTLE_SHORT_MASK)
- p->castling |= WHITE_SHORT;
- if (ch->flags1 & BLACK_CASTLE_LONG_MASK)
- p->castling |= BLACK_LONG;
- if (ch->flags1 & BLACK_CASTLE_SHORT_MASK)
- p->castling |= BLACK_SHORT;
- } else
- game->flags |= GAME_INITIAL_POSITION;
-
- return TRUE;
- }
-
-
- bool
- extractMovesCbGame(CbGame cg, Game game)
- { int plies = cg->movesLength;
- unsigned char *comments;
- Position pos;
- Move move;
- int i;
- int n;
-
- if (containsVariationsGameP(game))
- return extractVariationsCbGame(cg, game);
-
- comments = cg->comments;
- pos = newPosition();
-
- for (i=0; i<plies; i++)
- { if (cg->moves[i] == START_VARIATION || cg->moves[i] == END_VARIATION)
- { setError(ERR_VARIATION_SEEN);
- freePosition(pos);
- return FALSE;
- }
-
- if (i == 0)
- move = game->firstMove = newMove();
- else
- move = move->next = newMove();
-
- n = cg->moves[i] & 0x7f;
- if (!getMovePosition(pos,n,move))
- { setError(ERR_CANNOT_INTERPRET_MOVE);
- freePosition(pos);
- return FALSE;
- }
- doMovePosition(pos, move);
- if (cg->moves[i] & 0x80) /* Comment */
- comments = commentMove(move, comments);
- if (foundError())
- return FALSE;
- }
-
- game->plies = plies;
- if (game->moves != (plies+1)/2)
- { setError(ERR_MOVE_COUNT_INCORRECT);
- freePosition(pos);
- return FALSE;
- }
-
- freePosition(pos);
-
- return TRUE;
- }
-
-
- /* The code below is a bit "hairy".
- */
-
- #define MAX_LEVELS (MAX_LEVEL_NESTING*2)
-
- static bool
- extractVariationsCbGame(CbGame cg, Game game)
- { int l;
- int i;
- int j;
- int v;
- int n;
- unsigned char *comments;
- Position pos;
- Position variations[MAX_LEVELS]; /* Positions at given level */
- Move currentMoves[MAX_LEVELS]; /* Current move at given level */
-
- v = 0; /* Depth of variation */
- j = 0; /* Moves seen */
- l = 0; /* Plies seen */
- comments = cg->comments;
-
- for (i=0; i<MAX_LEVELS; i++)
- { variations[i] = newPosition();
- currentMoves[i] = NULL;
- }
-
- for (i=0; i<cg->movesLength; i++)
- { Move move;
-
- if (cg->moves[i] == START_VARIATION)
- { v += 2;
- copyPosition(variations[v], variations[v-1]);
- currentMoves[v] = NULL;
- continue;
- }
-
- if ( cg->moves[i] == END_VARIATION
- && (i+1) < cg->movesLength
- && cg->moves[i+1] == START_VARIATION)
- { copyPosition(variations[v], variations[v-1]);
- i++;
- currentMoves[v] = NULL;
- continue;
- }
-
- if (cg->moves[i] == END_VARIATION)
- { v -= 2;
- continue;
- }
-
- if ((i+1) < cg->movesLength && cg->moves[i+1] == START_VARIATION)
- { copyPosition(variations[v+1], variations[v]);
- currentMoves[v+1] = NULL;
- }
-
- pos = variations[v];
- move = currentMoves[v];
-
- if (v == 0)
- { if (move == NULL)
- move = game->firstMove = newMove();
- else
- move = move->next = newMove();
- } else
- { if (move == NULL)
- { Move alternative;
-
- move = newMove();
- alternative = currentMoves[v-2];
- while (alternative->alternative)
- alternative = alternative->alternative;
- alternative->alternative = move;
- } else
- move = move->next = newMove();
- }
-
- currentMoves[v] = move;
-
- { if (pos->toMove == WHITE && v == 0)
- j++;
- n = cg->moves[i] & 0x7f;
- if (!getMovePosition(pos,n,move) /* || (l>=m) */)
- { setError(ERR_CANNOT_INTERPRET_MOVE);
- goto errorFound;
- }
- doMovePosition(pos, move);
- if (cg->moves[i] & 0x80) /* Comment */
- comments = commentMove(move, comments);
- if (v == 0)
- l++;
- if (foundError())
- goto errorFound;
- }
- }
-
- for (i=0; i<MAX_LEVELS; i++)
- freePosition(variations[i]);
-
- game->plies = l;
- if (game->moves != j)
- { setError(ERR_MOVE_COUNT_INCORRECT);
- return FALSE;
- }
-
- return TRUE;
-
- errorFound:
- for (i=0; i<MAX_LEVELS; i++)
- freePosition(variations[i]);
- return FALSE;
- }
-
-
- /*------------------------------------------------------------
- * Debugging
- *------------------------------------------------------------*/
-
- void
- dumpCommentsCbGame(CbGame cg, FILE *fd)
- { unsigned char *s;
- int i;
-
- if (cg->commentLength == 0)
- return;
-
- fprintf(fd, "Comments (%x; %d):", (int) cg->comments, cg->commentLength);
- for (i=0, s=cg->comments; i<cg->commentLength; i++, s++)
- { if (*s == 0xff)
- fprintf(fd, "\n");
- fprintf(fd, "%03o ", *s);
- }
- fprintf(fd, "\n");
- }
-